home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / sound / msm5205.c < prev    next >
C/C++ Source or Header  |  2000-04-23  |  8KB  |  322 lines

  1. /*
  2.  *   streaming ADPCM driver
  3.  *   by Aaron Giles
  4.  *
  5.  *   Library to transcode from an ADPCM source to raw PCM.
  6.  *   Written by Buffoni Mirko in 08/06/97
  7.  *   References: various sources and documents.
  8.  *
  9.  *     HJB 08/31/98
  10.  *     modified to use an automatically selected oversampling factor
  11.  *     for the current Machine->sample_rate
  12.  *
  13.  *     01/06/99
  14.  *    separate MSM5205 emulator form adpcm.c and some fix
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <math.h>
  20.  
  21. #include "driver.h"
  22. #include "msm5205.h"
  23.  
  24. /*
  25.  * ADPCM lockup tabe
  26.  */
  27.  
  28. /* step size index shift table */
  29. static int index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
  30.  
  31. /* lookup table for the precomputed difference */
  32. static int diff_lookup[49*16];
  33.  
  34. /*
  35.  *   Compute the difference table
  36.  */
  37.  
  38. static void ComputeTables (void)
  39. {
  40.     /* nibble to bit map */
  41.     static int nbl2bit[16][4] =
  42.     {
  43.         { 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1},
  44.         { 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1},
  45.         {-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1},
  46.         {-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1}
  47.     };
  48.  
  49.     int step, nib;
  50.  
  51.     /* loop over all possible steps */
  52.     for (step = 0; step <= 48; step++)
  53.     {
  54.         /* compute the step value */
  55.         int stepval = floor (16.0 * pow (11.0 / 10.0, (double)step));
  56.  
  57.         /* loop over all nibbles and compute the difference */
  58.         for (nib = 0; nib < 16; nib++)
  59.         {
  60.             diff_lookup[step*16 + nib] = nbl2bit[nib][0] *
  61.                 (stepval   * nbl2bit[nib][1] +
  62.                  stepval/2 * nbl2bit[nib][2] +
  63.                  stepval/4 * nbl2bit[nib][3] +
  64.                  stepval/8);
  65.         }
  66.     }
  67. }
  68.  
  69. /*
  70.  *
  71.  *    MSM 5205 ADPCM chip:
  72.  *
  73.  *    Data is streamed from a CPU by means of a clock generated on the chip.
  74.  *
  75.  *    A reset signal is set high or low to determine whether playback (and interrupts) are occuring
  76.  *
  77.  */
  78.  
  79. struct MSM5205Voice
  80. {
  81.     int stream;             /* number of stream system      */
  82.     void *timer;              /* VCLK callback timer          */
  83.     int data;               /* next adpcm data              */
  84.     int vclk;               /* vclk signal (external mode)  */
  85.     int reset;              /* reset pin signal             */
  86.     int prescaler;          /* prescaler selector S1 and S2 */
  87.     int bitwidth;           /* bit width selector -3B/4B    */
  88.     int signal;             /* current ADPCM signal         */
  89.     int step;               /* current ADPCM step           */
  90. };
  91.  
  92. static const struct MSM5205interface *msm5205_intf;
  93. static struct MSM5205Voice msm5205[MAX_MSM5205];
  94.  
  95. /* stream update callbacks */
  96. static void MSM5205_update(int chip,INT16 *buffer,int length)
  97. {
  98.     struct MSM5205Voice *voice = &msm5205[chip];
  99.  
  100.     /* if this voice is active */
  101.     if(voice->signal)
  102.     {
  103.         short val = voice->signal * 16;
  104.         while (length)
  105.         {
  106.             *buffer++ = val;
  107.             length--;
  108.         }
  109.     }
  110.     else
  111.         memset (buffer,0,length*sizeof(INT16));
  112. }
  113.  
  114. /* timer callback at VCLK low eddge */
  115. static void MSM5205_vclk_callback(int num)
  116. {
  117.     struct MSM5205Voice *voice = &msm5205[num];
  118.     int val;
  119.     int new_signal;
  120.     /* callback user handler and latch next data */
  121.     if(msm5205_intf->vclk_interrupt[num]) (*msm5205_intf->vclk_interrupt[num])(num);
  122.  
  123.     /* reset check at last hieddge of VCLK */
  124.     if(voice->reset)
  125.     {
  126.         new_signal = 0;
  127.         voice->step = 0;
  128.     }
  129.     else
  130.     {
  131.         /* update signal */
  132.         /* !! MSM5205 has internal 12bit decoding, signal width is 0 to 8191 !! */
  133.         val = voice->data;
  134.         new_signal = voice->signal + diff_lookup[voice->step * 16 + (val & 15)];
  135.         if (new_signal > 2047) new_signal = 2047;
  136.         else if (new_signal < -2048) new_signal = -2048;
  137.         voice->step += index_shift[val & 7];
  138.         if (voice->step > 48) voice->step = 48;
  139.         else if (voice->step < 0) voice->step = 0;
  140.     }
  141.     /* update when signal changed */
  142.     if( voice->signal != new_signal)
  143.     {
  144.         stream_update(voice->stream,0);
  145.         voice->signal = new_signal;
  146.     }
  147. }
  148. /*
  149.  *    Start emulation of an MSM5205-compatible chip
  150.  */
  151.  
  152. int MSM5205_sh_start (const struct MachineSound *msound)
  153. {
  154.     int i;
  155.  
  156.     /* save a global pointer to our interface */
  157.     msm5205_intf = msound->sound_interface;
  158.  
  159.     /* compute the difference tables */
  160.     ComputeTables ();
  161.  
  162.     /* initialize the voices */
  163.     memset (msm5205, 0, sizeof (msm5205));
  164.  
  165.     /* stream system initialize */
  166.     for (i = 0;i < msm5205_intf->num;i++)
  167.     {
  168.         struct MSM5205Voice *voice = &msm5205[i];
  169.         char name[20];
  170.         sprintf(name,"MSM5205 #%d",i);
  171.         voice->stream = stream_init(name,msm5205_intf->mixing_level[i],
  172.                                 Machine->sample_rate,i,
  173.                                 MSM5205_update);
  174.     }
  175.     /* initialize */
  176.     MSM5205_sh_reset();
  177.     /* success */
  178.     return 0;
  179. }
  180.  
  181. /*
  182.  *    Stop emulation of an MSM5205-compatible chip
  183.  */
  184.  
  185. void MSM5205_sh_stop (void)
  186. {
  187. }
  188.  
  189. /*
  190.  *    Update emulation of an MSM5205-compatible chip
  191.  */
  192.  
  193. void MSM5205_sh_update (void)
  194. {
  195. }
  196.  
  197. static void MSM5205_set_timer(int num,int select)
  198. {
  199.     struct MSM5205Voice *voice = &msm5205[num];
  200.     static int prescaler_table[4] = {96,48,64,0};
  201.     int prescaler = prescaler_table[select&0x03];
  202.  
  203.     if( voice->prescaler != prescaler )
  204.     {
  205.         /* remove VCLK timer */
  206.         if(voice->timer)
  207.         {
  208.             timer_remove(voice->timer);
  209.             voice->timer = 0;
  210.         }
  211.         voice->prescaler = prescaler;
  212.         /* timer set */
  213.         if( prescaler )
  214.         {
  215.             voice->timer =
  216.                 timer_pulse (TIME_IN_HZ (msm5205_intf->baseclock / prescaler), num, MSM5205_vclk_callback);
  217.         }
  218.     }
  219. }
  220.  
  221. /*
  222.  *    Reset emulation of an MSM5205-compatible chip
  223.  */
  224. void MSM5205_sh_reset(void)
  225. {
  226.     int i;
  227.  
  228.     /* bail if we're not emulating sound */
  229.     if (Machine->sample_rate == 0)
  230.         return;
  231.  
  232.     for (i = 0; i < msm5205_intf->num; i++)
  233.     {
  234.         struct MSM5205Voice *voice = &msm5205[i];
  235.         /* initialize work */
  236.         voice->data    = 0;
  237.         voice->vclk    = 0;
  238.         voice->reset   = 0;
  239.         voice->signal  = 0;
  240.         voice->step    = 0;
  241.         /* timer set */
  242.         MSM5205_set_timer(i,msm5205_intf->select[i] & 0x03);
  243.         /* bitwidth reset */
  244.         msm5205[i].bitwidth = msm5205_intf->select[i]&0x04 ? 4 : 3;
  245.     }
  246. }
  247.  
  248. /*
  249.  *    Handle an update of the vclk status of a chip (1 is reset ON, 0 is reset OFF)
  250.  *    This function can use selector = MSM5205_SEX only
  251.  */
  252. void MSM5205_vclk_w (int num, int vclk)
  253. {
  254.     /* range check the numbers */
  255.     if (num >= msm5205_intf->num)
  256.     {
  257.         logerror("error: MSM5205_vclk_w() called with chip = %d, but only %d chips allocated\n", num, msm5205_intf->num);
  258.         return;
  259.     }
  260.     if( msm5205[num].prescaler != 0 )
  261.     {
  262.         logerror("error: MSM5205_vclk_w() called with chip = %d, but VCLK selected master mode\n", num);
  263.     }
  264.     else
  265.     {
  266.         if( msm5205[num].vclk != vclk)
  267.         {
  268.             msm5205[num].vclk = vclk;
  269.             if( !vclk ) MSM5205_vclk_callback(num);
  270.         }
  271.     }
  272. }
  273.  
  274. /*
  275.  *    Handle an update of the reset status of a chip (1 is reset ON, 0 is reset OFF)
  276.  */
  277.  
  278. void MSM5205_reset_w (int num, int reset)
  279. {
  280.     /* range check the numbers */
  281.     if (num >= msm5205_intf->num)
  282.     {
  283.         logerror("error: MSM5205_reset_w() called with chip = %d, but only %d chips allocated\n", num, msm5205_intf->num);
  284.         return;
  285.     }
  286.     msm5205[num].reset = reset;
  287. }
  288.  
  289. /*
  290.  *    Handle an update of the data to the chip
  291.  */
  292.  
  293. void MSM5205_data_w (int num, int data)
  294. {
  295.     if( msm5205[num].bitwidth == 4)
  296.         msm5205[num].data = data & 0x0f;
  297.     else
  298.         msm5205[num].data = (data & 0x07)<<1; /* unknown */
  299. }
  300.  
  301. /*
  302.  *    Handle an change of the selector
  303.  */
  304.  
  305. void MSM5205_selector_w (int num, int select)
  306. {
  307.     struct MSM5205Voice *voice = &msm5205[num];
  308.  
  309.     stream_update(voice->stream,0);
  310.     MSM5205_set_timer(num,select);
  311. }
  312. /* bitsel = -3B/4B pin : 0= 3bit , 1=4bit */
  313. void MSM5205_bitwidth_w (int num, int bitsel)
  314. {
  315.     int bitwidth = bitsel ? 4 : 3;
  316.     if( msm5205[num].bitwidth != bitwidth )
  317.     {
  318.         stream_update(msm5205[num].stream,0);
  319.         msm5205[num].bitwidth = bitwidth;
  320.     }
  321. }
  322.